#ifndef OPCODE_H
#define OPCODE_H
#include "global.h"
#include "object.h"

namespace tinyscript{
namespace internal{
namespace opcode {

enum {
	OP_ADD = 0,
	OP_SUB ,
	OP_MUL ,
	OP_DIV ,
	OP_MOD ,
	OP_CMP ,
	OP_TEST,
	OP_CALL,
	OP_RET ,
	OP_JMP ,
	OP_INT ,
	OP_NOP,
	OP_PAUSE
};

enum {
	DUMMY = 0,
	INT = 1,
	FLOAT = 2,
	REF = 3
};

enum {
	PC = 1 
};

#define OPCODE2(OPE,LT,RT) \
	(((0xffffffff)&((OPE)<<4)) & (((LT) << 2)) & (RT))

#define OPCODE1(OPE,T) \
	(((0xffffffff)&((OPE)<<2)) & (LT))

#define OPCODE0(OPE) \
	(OPE)

#define OPCODE(N) \
	OPCODE##N

#define OP2(O,L,R) \
	O##_##L##_##R

#define OP1(O,A) \
	O##_##A

#define OP0(O) \
	O

#define OP(N) \
	OP##N

#define E2(O,L,R) \
	OP(2)(O,L,R) = OPCODE(2)(O,L,R)

#define E1(O,A) \
	OP(1)(O,A) = OPCODE(1)(O,A)

#define E0(O) \
	OP(0)(O) = OPCODE(0)(O)

#define E(N) \
	E##N

// OPCODE definition

enum {
	// OP_ADD
	E(2)(OP_ADD,REF,REF),
	E(2)(OP_ADD,REF,INT),
	E(2)(OP_ADD,REF,FLOAT),
	E(2)(OP_ADD,INT,FLOAT),
	E(2)(OP_ADD,INT,REF),
	E(2)(OP_ADD,INT,INT),
	E(2)(OP_ADD,FLOAT,FLOAT),
	E(2)(OP_ADD,FLOAT,INT),
	E(2)(OP_ADD,FLOAT,REF),
	// OP_SUB
	E(2)(OP_SUB,REF,REF),
	E(2)(OP_SUB,REF,INT),
	E(2)(OP_SUB,REF,FLOAT),
	E(2)(OP_SUB,INT,FLOAT),
	E(2)(OP_SUB,INT,REF),
	E(2)(OP_SUB,INT,INT),
	E(2)(OP_SUB,FLOAT,FLOAT),
	E(2)(OP_SUB,FLOAT,INT),
	E(2)(OP_SUB,FLOAT,REF),
	// OP_DIV
	E(2)(OP_DIV,REF,REF),
	E(2)(OP_DIV,REF,INT),
	E(2)(OP_DIV,REF,FLOAT),
	E(2)(OP_DIV,INT,FLOAT),
	E(2)(OP_DIV,INT,REF),
	E(2)(OP_DIV,INT,INT),
	E(2)(OP_DIV,FLOAT,FLOAT),
	E(2)(OP_DIV,FLOAT,INT),
	E(2)(OP_DIV,FLOAT,REF),
	// OP_MUL
	E(2)(OP_MUL,REF,REF),
	E(2)(OP_MUL,REF,INT),
	E(2)(OP_MUL,REF,FLOAT),
	E(2)(OP_MUL,INT,FLOAT),
	E(2)(OP_MUL,INT,REF),
	E(2)(OP_MUL,INT,INT),
	E(2)(OP_MUL,FLOAT,FLOAT),
	E(2)(OP_MUL,FLOAT,INT),
	E(2)(OP_MUL,FLOAT,REF),
	// OP_MOD
	E(2)(OP_MOD,REF,REF),
	E(2)(OP_MOD,REF,INT),
	E(2)(OP_MOD,INT,REF),
	E(2)(OP_MOD,INT,INT),
	// OP_CMP
	E(2)(OP_CMP,REF,REF),
	E(2)(OP_CMP,REF,INT),
	E(2)(OP_CMP,REF,FLOAT),
	E(2)(OP_CMP,INT,FLOAT),
	E(2)(OP_CMP,INT,REF),
	E(2)(OP_CMP,INT,INT),
	E(2)(OP_CMP,FLOAT,FLOAT),
	E(2)(OP_CMP,FLOAT,INT),
	E(2)(OP_CMP,FLOAT,REF),
	// OP_TEST
	E(1)(OP_TEST,PC),
	// OP_CALL
	E(1)(OP_CALL,PC),
	// OP_JMP
	E(1)(OP_JMP,PC),
	// OP_INT
	E(1)(OP_INT,INT),
	// OP_NOP
	E(0)(OP_NOP),
	E(0)(OP_PAUSE),
	// OP_RET
	E(0)(OP_RET)

};


const char* GetOPCodeStr( int cd );

}// namespace opcode
}// namespace internal
}// namespace tinyscript

#endif // OPCODE_H
